//
// Created by Tony on 2024/6/6.
//

#include "ClassTable.h"
#include "../../common/KeyWords.h"
#include "Class.h"
#include "NativeMethodTable.h"
#include <iostream>
#include <memory>
#include <sstream>

namespace RtCode {

using std::make_shared;

vector<string> G_PRIMITIVE_TYPES{KeyWords::INT,  KeyWords::DOUBLE, KeyWords::BOOLEAN,
                                 KeyWords::CHAR, KeyWords::STRING, KeyWords::NIL,
                                 KeyWords::VOID};

void ClassTable::init() {
    if (mIsInited) {
        return;
    }
    mIsInited = true;

    mClassTable.push_back(nullptr); // id = 0 is invalid class

    // init primitive types
    for (auto& typeName : G_PRIMITIVE_TYPES) {
        auto clazz = make_shared<Class>(typeName, shared_from_this());
        addClass(clazz);
    }

    mNativeMethodTable = make_shared<NativeMethodTable>();
    mNativeMethodTable->add(Runtime::ENTRY_CLASS_NAME, "println", [](RtData::Frame& frame) {
        auto slot = frame.getSlot(0);
        std::cout << slot.getInt64() << std::endl;
    });
}

int32_t ClassTable::addClass(const shared_ptr<Class>& clazz) {
    this->mClassTable.push_back(clazz);
    auto classId = static_cast<int32_t>(this->mClassTable.size() - 1);
    this->mClassIdTable.emplace(clazz->getName(), classId);
    return classId;
}

shared_ptr<Class> ClassTable::getClassById(int32_t classId) {
    if (classId >= mClassTable.size()) {
        return nullptr;
    }
    return this->mClassTable[classId];
}

shared_ptr<Class> ClassTable::getClassByName(const string& className) {
    auto clazz = this->mClassIdTable.find(className);
    if (clazz == this->mClassIdTable.end()) {
        return nullptr;
    }
    auto index = clazz->second;
    return this->mClassTable[index];
}

int32_t ClassTable::getClassIdByName(const string& className) {
    auto clazz = this->mClassIdTable.find(className);
    if (clazz == this->mClassIdTable.end()) {
        return -1;
    }
    return clazz->second;
}

string ClassTable::toString() {
    using std::endl;
    std::stringstream ss;
    for (size_t i = G_PRIMITIVE_TYPES.size() + 1; i < mClassTable.size(); i++) {
        ss << endl << mClassTable[i]->toString() << endl;
    }
    return ss.str();
}

} // namespace RtCode
